package com.uniview.util;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Enumeration;

import org.apache.tools.tar.TarEntry;
import org.apache.tools.tar.TarInputStream;
import org.apache.tools.zip.ZipEntry;
import org.apache.tools.zip.ZipFile;
import org.apache.tools.zip.ZipOutputStream;

import com.github.junrar.Archive;
import com.github.junrar.rarfile.FileHeader;

/**
 * zip or rar 文件解压缩工具类
 * 
 */
public class ZipRarUtil {

	private static final int BUFFEREDSIZE = 1024;

	/**
	 * 解压zip格式的压缩文件到指定位置
	 * 
	 * @param sourceZip
	 *            压缩文件
	 * @param destDir
	 *            解压目录
	 * @throws Exception
	 */
	public synchronized static boolean unzip(String sourceZip, String destDir)
			throws Exception {
		File dest = new File(destDir);
		if (dest != null && !dest.exists())
			dest.mkdirs();
		File f = new File(sourceZip);
		ZipFile zipFile = new ZipFile(sourceZip,"UTF-8");
		if ((!f.exists()) && (f.length() <= 0)) {
			throw new Exception(sourceZip + "解压文件不存在!");
		}

		String strtemp = null;
		Enumeration<?> e = zipFile.getEntries();
		FileOutputStream fos = null;
		BufferedOutputStream bos = null;
		InputStream ism = null;
		BufferedInputStream bis = null;
		while (e.hasMoreElements()) {
			ZipEntry zipEnt = (ZipEntry) e.nextElement();
			strtemp = destDir + File.separator + zipEnt.getName();
			if (zipEnt.isDirectory()) {
				File dir = new File(strtemp);
				if (!dir.exists())
					dir.mkdirs();
				continue;
			} else {
				try {
					// 读写文件
					ism = zipFile.getInputStream(zipEnt);
					bis = new BufferedInputStream(ism);
					if (!new File(strtemp).getParentFile().exists())
						new File(strtemp).getParentFile().mkdirs();
					// 建目录
					String strSubdir = zipEnt.getName();
					for (int i = 0; i < strSubdir.length(); i++) {
						if (strSubdir.substring(i, i + 1).equalsIgnoreCase(
								File.separator)) {
							String temp = destDir + File.separator
									+ strSubdir.substring(0, i);
							File subdir = new File(temp);
							if (!subdir.exists())
								subdir.mkdirs();
						}
					}
					fos = new FileOutputStream(strtemp);
					bos = new BufferedOutputStream(fos);
					int c = 0;
					while ((c = bis.read()) != -1) {
						bos.write((byte) c);
					}
					fos.flush();
					bos.flush();
				} finally {
					if (ism != null)
						ism.close();
					if (bis != null)
						bis.close();
					if (bos != null)
						bos.close();
					if (fos != null)
						fos.close();
				}
			}
		}
		if (zipFile != null)
			zipFile.close();
		return true;
	}

	/**
	 * 压缩zip格式的压缩文件
	 * 
	 * @param inputFilename
	 *            压缩的文件或文件夹及详细路径
	 * @param sourceZip
	 *            输出文件名称及详细路径
	 * @throws IOException
	 */
	public synchronized static boolean zip(String inputFilename,
			String sourceZip) throws Exception {
		return zip(new File(inputFilename), sourceZip);
	}

	/**
	 * 压缩zip格式的压缩文件
	 * 
	 * @param inputFile
	 *            需压缩文件
	 * @param sourceZip
	 *            输出文件及详细路径
	 * @throws IOException
	 */
	public synchronized static boolean zip(File inputFile, String sourceZip)
			throws Exception {
		ZipOutputStream out = null;
		try {
			out = new ZipOutputStream(new FileOutputStream(sourceZip));
			return zip(inputFile, out, "");
		} finally {
			if (out != null)
				out.close();
		}
	}

	/**
	 * 压缩zip格式的压缩文件
	 * 
	 * @param inputFile
	 *            需压缩文件
	 * @param out
	 *            输出压缩文件
	 * @param base
	 *            结束标识
	 * @throws IOException
	 */
	private synchronized static boolean zip(File inputFile,
			ZipOutputStream out, String base) throws IOException {
		if (inputFile.isDirectory()) {
			File[] inputFiles = inputFile.listFiles();
			out.putNextEntry(new ZipEntry(base + File.separator));
			base = base.length() == 0 ? "" : base + File.separator;
			for (int i = 0; i < inputFiles.length; i++) {
				zip(inputFiles[i], out, base + inputFiles[i].getName());
			}
		} else {
			if (base.length() > 0) {
				out.putNextEntry(new ZipEntry(base));
			} else {
				out.putNextEntry(new ZipEntry(inputFile.getName()));
			}
			FileInputStream in = null;
			try {
				in = new FileInputStream(inputFile);
				int c = 0;
				byte[] by = new byte[BUFFEREDSIZE];
				while ((c = in.read(by)) != -1) {
					out.write(by, 0, c);
				}
				out.flush();
			} finally {
				if (in != null)
					in.close();
			}
		}
		return true;
	}

	/**
	 * 解压rar格式的压缩文件到指定目录下
	 * 
	 * @param rarFileName
	 *            压缩文件
	 * @param destDir
	 *            解压目录
	 * @throws Exception
	 */
	public synchronized static boolean unrar(String sourceRar, String destDir)
			throws Exception {
		Archive a = null;
		FileOutputStream fos = null;
		try {
			if (!new File(sourceRar).exists())
				throw new Exception(sourceRar + "解压文件不存在!");
			a = new Archive(new File(sourceRar));
			FileHeader fh = null;
			while ((fh = a.nextFileHeader()) != null) {
				if (!fh.isDirectory()) {
					// 1 根据不同操作系统识别文件类型
					String compressFileName = fh.getFileNameString().trim();
					String destFileName = "";
					String destDirName = "";
					if (File.separator.equals("/")) { // 非 windows系统
						destFileName = destDir
								+ compressFileName.replaceAll("\\\\", "/");
						destDirName = destFileName.substring(0,
								destFileName.lastIndexOf("/"));
					} else { // windows系统
						destFileName = destDir
								+ compressFileName.replaceAll("/", "\\\\");
						destDirName = destFileName.substring(0,
								destFileName.lastIndexOf("\\"));
					}
					// 2 创建文件夹
					File dir = new File(destDirName);
					if (!dir.exists()) {
						dir.mkdirs();
					}
					// 3 解压缩文件
					try {
						fos = new FileOutputStream(new File(destFileName));
						a.extractFile(fh, fos);
					} finally {
						if (fos != null)
							fos.close();
					}
				}
			}
			return true;
		} finally {
			if (a != null)
				a.close();
			if (fos != null)
				fos.close();
			if (a != null)
				a.close();
		}
	}

	/**
	 * 解压 tar 压缩包
	 * 
	 * @param file
	 * @param outputDir
	 * @throws IOException
	 */
	public synchronized static boolean untar(String sourceTar, String destDir)
			throws Exception {
		TarInputStream tarIn = null;
		FileInputStream fim = null;
		try {
			if (!new File(sourceTar).exists())
				throw new Exception(sourceTar + "解压文件不存在!");
			fim = new FileInputStream(new File(sourceTar));
			tarIn = new TarInputStream(fim, BUFFEREDSIZE);
			if (!new File(destDir).exists())
				new File(destDir).mkdirs();
			TarEntry entry = null;
			while ((entry = tarIn.getNextEntry()) != null) {
				if (entry.isDirectory()) {// 目录
					if (!new File(destDir + File.separator + entry.getName())
							.exists())
						new File(destDir + File.separator + entry.getName())
								.mkdirs();
				} else {// 文件
					File tmpFile = new File(destDir + File.separator
							+ entry.getName());
					if (!tmpFile.exists())
						tmpFile.mkdirs();
					// 创建输出目录
					OutputStream out = null;
					try {
						out = new FileOutputStream(tmpFile);
						int length = 0;
						byte[] b = new byte[BUFFEREDSIZE];
						while ((length = tarIn.read(b)) != -1) {
							out.write(b, 0, length);
						}
						out.flush();
					} finally {
						if (out != null)
							out.close();
					}
				}
			}
			return true;
		} finally {
			if (fim != null)
				fim.close();
			if (tarIn != null)
				tarIn.close();
		}
	}

	/**
	 * 解压所有zip/rar/tar压缩包到指定目录下
	 * 
	 * @param sourcePackage
	 *            解压包
	 * @param destDir
	 *            解压到指定目录
	 * @param isDelRource
	 *            解压后是否删除源文件
	 * @return
	 * @throws Exception
	 */
	public synchronized static boolean unAll(String sourcePackage,
			String destDir, boolean isDelRource) throws Exception {
		if (!new File(sourcePackage).exists())
			throw new Exception(sourcePackage + "解压文件不存在!");
		boolean isOK = false;
		if (sourcePackage.toLowerCase().endsWith(".zip")) { // 解压zip
			isOK = unzip(sourcePackage, destDir);
		} else if (sourcePackage.toLowerCase().endsWith(".rar")) { // 解压rar
			isOK = unrar(sourcePackage, destDir);
		} else if (sourcePackage.toLowerCase().endsWith(".tar")) { // 解压tar
			isOK = untar(sourcePackage, destDir);
		} else {
			return isOK;
		}
		if (isOK && isDelRource) {
			// 删除解压包源文件
			new File(sourcePackage).delete();
		}
		return isOK;
	}

}
